﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using SharePointBrowser.Properties;

namespace SharePointBrowser
{
    public abstract class SlidingListControl : UserControl
    {

        public SlidingListControl()
        {
            // Set control size (to maximum visible area)
            this.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);

            // Initialize graphics and double buffering
            Initialize_Graphics();

            // Initialize navigation
            Initialize_Buttons();

            // Initialize scrolling
            Initialize_Scrolling();
        }

        protected List<ISlidingListItem> internalDataList { get; set; }

        public abstract void LoadData();

        private Graphics graphics;
        private Bitmap doubleBuffer;
        ImageAttributes transparency;
        private Bitmap backgroundImage;

        protected delegate void UIThreadDelegate();

        private void Initialize_Graphics()
        {
            // Initialize "writeable memory bitmap"
            doubleBuffer = new Bitmap(this.Width, this.Height);
            graphics = Graphics.FromImage(doubleBuffer);

            // Set transparency color to "Black"
            transparency = new ImageAttributes();
            transparency.SetColorKey(Color.Black, Color.Black);

            backgroundImage = DrawingHelper.ResizeBitmap(Resources.Background, Size);
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // Draw background
            graphics.DrawImage(backgroundImage, 0, 0);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            for (int i = 0; (internalDataList != null) && i < internalDataList.Count; i++)
                internalDataList[i].Paint(graphics);

            e.Graphics.DrawImage(doubleBuffer, 0, 0);
        }

        protected void CustomInvalidate()
        {
            this.Invalidate();
            //this.Update();
        }

        protected bool isMainPressed { get; set; }

        private void Initialize_Buttons() { }

        Point mouseDown = Point.Empty;
        Point mouseLast = Point.Empty;

        protected int SlidingPanel_TranslateY; // Y Translate trasformation for the Sliding Panel element
        protected int SlidingPanel_Height;

        private bool _IsScrollingActivated;
        protected bool _IsDataLoading { get; set; }

        public void Initialize_Scrolling()
        {
            if (!_IsScrollingActivated)
            {
                // General form handlers
                this.MouseDown += new MouseEventHandler(SlidingPanel_MouseDown);
                this.MouseUp += new MouseEventHandler(SlidingPanel_MouseUp);
                this.MouseMove += new MouseEventHandler(SlidingPanel_MouseMove);

                // Initialize Inertial System
                Invoke(new UIThreadDelegate(Initialize_InertialSystem));
                _IsScrollingActivated = true;
            }
        }

        private void ScrollItems(int delta)
        {
            if (_IsDataLoading)
                return;

            // Check boundary
            if (SlidingPanel_TranslateY + delta > 20)
                delta = 0;
            else if (SlidingPanel_TranslateY + SlidingPanel_Height + delta < 260)
                delta = 0;

            SlidingPanel_TranslateY += delta;

            if (internalDataList != null)
                internalDataList.ForEach(item => item.Location = new Point(item.Location.X, item.Location.Y + delta));

            this.CustomInvalidate();
        }

        void SlidingPanel_MouseDown(object sender, MouseEventArgs e)
        {
            mouseIsDown = true;
            mouseDown = new Point(e.X, e.Y);
            mouseLast = mouseDown;
            {
                if (internalDataList != null)
                {
                    var selectedItem = internalDataList.Where(item => item.Rectangle.Contains(mouseDown)).FirstOrDefault();
                    if (selectedItem != null)
                        selectedItem.Pressed = true;
                }
            }
            this.CustomInvalidate();
        }

        void SlidingPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (!renderLockFlag)
            {
                renderLockFlag = true;
                int delta = e.Y - mouseLast.Y;
                mouseLast = new Point(e.X, e.Y);
                draggedDistance = delta;
                ScrollItems(delta);
                inertialTimer.Enabled = true;
            }
        }

        void SlidingPanel_MouseUp(object sender, MouseEventArgs e)
        {
            Point mouseUp = new Point(e.X, e.Y);
            if (Math.Abs(e.X - mouseDown.X) < 10 && Math.Abs(e.Y - mouseDown.Y) < 10)
            {
                internalDataList.ForEach(item => item.Selected = false);
                ISlidingListItem selectedItem = internalDataList.Where(IItem => IItem.Rectangle.Contains(mouseDown)).FirstOrDefault();
                if (selectedItem != null)
                {
                    selectedItem.Selected = true;
                    this.Update();
                    selectedItem.CallClickAction();
                }
            }

            if (renderLockFlag)
            {
                velocity = Math.Min(Math.Max(dragDistanceFactor * draggedDistance, -maxVelocity), maxVelocity);
                draggedDistance = 0;
                DoAutomaticMotion();
            }

            mouseIsDown = false;
            isMainPressed = false;

            this.CustomInvalidate();
        }

        private System.Windows.Forms.Timer inertialTimer;

        private bool renderLockFlag = false;
        private float velocity = 0.0f;
        private bool mouseIsDown = false;
        private float deaccelerationFactor = 0.8f;
        private float maxVelocity = 500.0f;
        private float dragDistanceFactor = 50.0f;
        private int draggedDistance = 0;
        private int heightPanel;

        private void Initialize_InertialSystem()
        {
            inertialTimer = new System.Windows.Forms.Timer();
            inertialTimer.Tick += new EventHandler(animationTimer_Tick);
            inertialTimer.Enabled = true;

            heightPanel = this.Size.Height;
        }

        private void animationTimer_Tick(object sender, EventArgs e)
        {
            renderLockFlag = false;
            DoAutomaticMotion();
        }

        private void DoAutomaticMotion()
        {
            if (!mouseIsDown)
            {
                velocity *= deaccelerationFactor;
                float elapsedTime = inertialTimer.Interval / 1000.0f;
                float deltaDistance = elapsedTime * velocity;
                //System.Diagnostics.Debug.WriteLine("DeltaDistance: " + deltaDistance);
                // If the velocity induced by the user dragging the list
                // results in a deltaDistance greater than 1.0f pixels 
                // then scroll the items that distance.
                if (Math.Abs(deltaDistance) >= 1.0f)
                {
                    ScrollItems((int)deltaDistance);
                }
                else
                {
                    inertialTimer.Enabled = false;
                }
            }
        }
    }
}